﻿#include "TrapRock.h"
#include "../../../Shared/Functions/Functions.h"
#include "../../../Shared/ServerPackets.h"

using namespace Server::MirDatabase;
namespace S = ServerPackets;

namespace Server::MirObjects::Monsters
{

    bool TrapRock::getCanAttack() const
    {
        return Visible && MonsterObject::getCanAttack();
    }

    bool TrapRock::getCanMove() const
    {
        return false;
    }

    bool TrapRock::getBlocking() const
    {
        return Visible && MonsterObject::getBlocking();
    }

    TrapRock::TrapRock(MonsterInfo *info) : MonsterObject(info)
    {
        Visible = false;
        VisibleTime = getEnvir()->getTime() + 2000;
        FirstAttack = true;
    }

    Server::MirObjects::MapObject *TrapRock::getTarget() const
    {
        return _target;
    }

    void TrapRock::setTarget(MapObject *value)
    {
        if (_target != nullptr && value != nullptr)
        {
            return;
        }
        if (_target != nullptr && value == nullptr)
        {
            _target->setInTrapRock(false);
        }
        _target = value;

        if (Visible && value == nullptr)
        {
            Die();
        }
    }

    void TrapRock::ProcessAI()
    {
        if (Dead)
        {
            return;
        }

        if (getEnvir()->getTime() > VisibleTime)
        {
            VisibleTime = getEnvir()->getTime() + 2000;

            bool visible = getTarget() != nullptr;

            if (!Visible && visible && !getTarget()->Dead && !getTarget()->getInTrapRock())
            {
                SpawnCorner = static_cast<unsigned char>(getEnvir()->Random->Next(4) * 2);
                if (Teleport(getCurrentMap(), Functions::PointMove(getTarget()->getCurrentLocation(), static_cast<MirDirection>(SpawnCorner), 1), false))
                {
                    ActionTime = getEnvir()->getTime() + 1000;
                    Show();
                    return;
                }
            }

            if (Visible && (getTarget()->Dead || getTarget()->getCurrentLocation() != TargetLocation))
            {
                Die();
                return;
            }
        }

        MonsterObject::ProcessAI();
    }

    void TrapRock::Attack()
    {
        if (!getTarget()->IsAttackTarget(this))
        {
            setTarget(nullptr);
            return;
        }

        if (!ChildRock)
        {
            S::ObjectRangeAttack *tempVar = new S::ObjectRangeAttack();
            tempVar->ObjectID = ObjectID;
            tempVar->Direction = getDirection();
            tempVar->Location = getCurrentLocation();
            tempVar->TargetID = getTarget()->ObjectID;
            Broadcast(tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
        }
        else
        {
            S::ObjectAttack *tempVar2 = new S::ObjectAttack();
            tempVar2->ObjectID = ObjectID;
            tempVar2->Direction = getDirection();
            tempVar2->Location = getCurrentLocation();
            Broadcast(tempVar2);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar2' statement was not added since tempVar2 was passed to a method or constructor. Handle memory management manually.
        }

        ActionTime = getEnvir()->getTime() + 300;
        AttackTime = getEnvir()->getTime() + AttackSpeed;

        if (getEnvir()->Random->Next(8) == 0 && !ChildRock)
        {
            Poison *tempVar3 = new Poison(), *this, *true;
            tempVar3->PType = PoisonType::Paralysis;
            tempVar3->Duration = 3;
            tempVar3->TickSpeed = 1000;
            getTarget()->ApplyPoison(tempVar3, this, true);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar3' statement was not added since tempVar3 was passed to a method or constructor. Handle memory management manually.
        }

        if (getTarget()->Dead)
        {
            Die();
        }
    }

    void TrapRock::Die()
    {
        if (!ChildRock)
        {
            if (getTarget() != nullptr)
            {
                if (getCurrentMap() == getTarget()->getCurrentMap() && Functions::InRange(getCurrentLocation(), getTarget()->getCurrentLocation(), 1))
                {
                    getTarget()->setInTrapRock(false);
                }
            }
            if (Info->HasDieScript && (getEnvir()->MonsterNPC != nullptr))
            {
                getEnvir()->MonsterNPC->Call(this,StringHelper::formatSimple("[@_DIE({0})]", Info->Index));
            }


            for (int i = SlaveList.size() - 1; i >= 0; i--)
            {
                if (!SlaveList[i]->Dead || SlaveList[i]->Node != nullptr)
                {
                    SlaveList[i]->Die();
                    SlaveList.erase(SlaveList.begin() + i);
                }
            }
        }

        MonsterObject::Die();
    }

    int TrapRock::Attacked(MonsterObject *attacker, int damage, DefenceType type)
    {
        if (ChildRock)
        {
            ParentRock->FirstAttack = false;
        }
        if (!ChildRock && FirstAttack == true)
        {
            Die();
            return 0;
        }
        return MonsterObject::Attacked(attacker, damage, type);
    }

    int TrapRock::Attacked(PlayerObject *attacker, int damage, DefenceType type, bool damageWeapon)
    {
        if (ChildRock)
        {
            ParentRock->FirstAttack = false;
        }
        if (!ChildRock && FirstAttack == true)
        {
            Die();
            return 0;
        }
        return MonsterObject::Attacked(attacker, damage, type, damageWeapon);
    }

    int TrapRock::Struck(int damage, DefenceType type)
    {
        return 0;
    }

    void TrapRock::ChangeHP(int amount)
    {
        if (ChildRock)
        {
            return;
        }

        MonsterObject::ChangeHP(amount);
    }

    void TrapRock::Turn(MirDirection dir)
    {
    }

    bool TrapRock::Walk(MirDirection dir)
    {
        return false;
    }

    void TrapRock::ProcessRoam()
    {
    }

    Packet *TrapRock::GetInfo()
    {
        if (!Visible)
        {
            return nullptr;
        }

        return MonsterObject::GetInfo();
    }

    void TrapRock::Show()
    {
        TargetLocation = getTarget()->getCurrentLocation();
        Visible = true;
        CellTime = ChildRock ? ParentRock->CellTime : getEnvir()->getTime() + 500;

        Broadcast(GetInfo());
        S::ObjectShow *tempVar = new S::ObjectShow();
        tempVar->ObjectID = ObjectID;
        Broadcast(tempVar);

        if (!ChildRock)
        {
            Poison *tempVar2 = new Poison(), *this, *true;
            tempVar2->PType = PoisonType::Paralysis;
            tempVar2->Duration = 3;
            tempVar2->TickSpeed = 1000;
            getTarget()->ApplyPoison(tempVar2,this, true);
            getTarget()->setInTrapRock(true);

            for (unsigned char i = 0; i <= 6; i += 2)
            {
                if (i == SpawnCorner)
                {
                    continue;
                }
                auto mob = GetMonster(getEnvir()->GetMonsterInfo(getName()));

                if (mob == nullptr)
                {
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar2' statement was not added since tempVar2 was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
                    return;
                }
                auto childmob = static_cast<TrapRock*>(mob);

                if (childmob->Spawn(getCurrentMap(), Functions::PointMove(getTarget()->getCurrentLocation(), static_cast<MirDirection>(i), 1)))
                {
                    if (getTarget() != nullptr)
                    {
                        childmob->setTarget(getTarget());
                    }

                    childmob->ChildRock = true;
                    childmob->ParentRock = this;
                    SlaveList.push_back(childmob);
                    childmob->Show();
                    childmob->ActionTime = this->ActionTime;
                    childmob->AttackTime = this->AttackTime;
                }
                else
                {
                    continue;
                }
            }

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar2' statement was not added since tempVar2 was passed to a method or constructor. Handle memory management manually.
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }
}
